//
// chat_message.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef CHAT_MESSAGE_HPP
#define CHAT_MESSAGE_HPP

#include <iomanip>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "log.h"

class Message
    {
public:
    enum
        {
        HEADER_LEN = 4
        };
    enum
        {
        MAX_BODY_LEN = 512
        };

    enum ContentType
        {
        UNKNOWN,
        CT_BINARY,
        CT_STRING,
        CT_MAX
        };

    Message(ContentType inCT = CT_BINARY) :
        body_length_(0)
        {
        conType = inCT;
        resetData();
        }

    void resetData()
        {
        std::memset(data_, 0, HEADER_LEN + MAX_BODY_LEN);
        }
    const char* data() const
        {
        return data_;
        }

    char* data()
        {
        return data_;
        }

    size_t length() const
        {
        return HEADER_LEN + body_length_;
        }

    size_t size() const
        {
        return HEADER_LEN + body_length_;
        }

    const char* body() const
        {
        return data_ + HEADER_LEN;
        }

    char* body()
        {
        return data_ + HEADER_LEN;
        }

    size_t body_length() const
        {
        return body_length_;
        }

    void body_length(size_t length)
        {
        body_length_ = length;
        if (body_length_ > MAX_BODY_LEN)
            body_length_ = MAX_BODY_LEN;
        }

    bool decode_header()
        {
        using namespace std;
        // For strncat and atoi.
        char header[HEADER_LEN + 1] = "";
        strncat(header, data_, HEADER_LEN);
        body_length_ = atoi(header);
        if (body_length_ > MAX_BODY_LEN)
            {
            body_length_ = 0;
            return false;
            }
        return true;
        }

    void encode_header()
        {
        using namespace std;
        // For sprintf and memcpy.
        char header[HEADER_LEN + 1] = "";
        sprintf(header, "%4d", body_length_);
        memcpy(data_, header, HEADER_LEN);
        }

    friend std::ostream & operator<<(std::ostream & os, const Message & msg)
        {
        os << "\n---Show Message Begin---" << std::endl;
        os << "body len=" << msg.body_length_ << "\n";
        os << "content:\n";

        if (msg.conType == CT_STRING)
            {
            os << (char *) msg.body();
            }
        else
            {

            char fillc = os.fill('0');

            for (unsigned int i = 0; i <= msg.body_length_
                    / sizeof(unsigned int); i++)
                os << std::hex << std::setw(sizeof(unsigned int))
                        << *((unsigned int *) msg.data_ + i) << ' ';
            os << std::setfill(fillc);
            }

        os << "\n---Show Message End---" << std::endl;

        return os;
        }

private:
    char data_[HEADER_LEN + MAX_BODY_LEN];
    size_t body_length_;
    ContentType conType;
    };

#endif // CHAT_MESSAGE_HPP
